package com.takeeasy.platform.persistence;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.takeeasy.platform.bizObject.IBizObject;
import com.takeeasy.platform.exception.PersistenceRuntimeExcption;
import com.takeeasy.platform.util.DBUtil;

public class PersistenceDaoImpl implements IPersistenceDao {
	private static final Logger logger = LoggerFactory.getLogger(PersistenceDaoImpl.class);

	private Connection conn;

	public PersistenceDaoImpl(Connection conn) {
		this.conn = conn;
	}

	@Override
	public Connection getConnection() {
		return this.conn;
	}

	@Override
	public boolean excute(String sql) {
		try {
			Statement stat = conn.createStatement();
			return stat.execute(sql);
		} catch (SQLException e) {
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

	@Override
	public boolean excute(String sql, List<?> params) {
		try {

			PreparedStatement stat = conn.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				stat.setObject(i + 1, params.get(i));
			}
			return stat.execute();
		} catch (SQLException e) {
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

	@Override
	public <E extends IBizObject> List<E> query(Class<E> bo, String sql) {
		logger.debug("执行SQL：" + sql);
		try {
			PreparedStatement stat = conn.prepareStatement(sql);
			ResultSet set = stat.executeQuery();
			return this.wrapResultSet(bo, set);
		} catch (SQLException e) {
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

	@Override
	public <E extends IBizObject> List<E> query(Class<E> bo, String sql, List<Object> params) {
		logger.debug("执行SQL：" + sql);
		try {
			PreparedStatement stat = conn.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				Object value = params.get(i);
				if (value == null) {
					continue;
				}
				stat.setObject(i + 1, value);
			}
			ResultSet set = stat.executeQuery();
			return this.wrapResultSet(bo, set);
		} catch (SQLException e) {
			logger.error(e.getMessage());
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

	@Override
	public <T extends IBizObject> T query(Class<T> bo) {
		return null;
	}

	@Override
	public <T extends IBizObject> boolean update(Class<T> bo) {
		return false;
	}

	@Override
	public <T extends IBizObject> boolean delete(Class<T> bo) {
		return false;
	}

	@Override
	public <E extends IBizObject> List<E> paginationQuery(Class<E> bo, Page page, String sql) {
		List<E> boList = new ArrayList<>();
		if (page == null) {
			this.query(bo, sql);
		} else {
			long count = this.countQuery(sql);
			page.setTotalRow(Integer.parseInt(String.valueOf(count)));
			if (page.getCurrentPage() > ((count % page.getRowPerPage()) != 0 ? count / page.getRowPerPage() + 1 : count / page.getRowPerPage())) {
				logger.warn("数据总数分页小于当前分页，数据可能将无法查询。");
			}
			StringBuffer sqlPage = new StringBuffer();
			sqlPage.append("select * from(").append(sql).append(") as tempSQLString LIMIT ")
					.append((page.getCurrentPage() - 1) * page.getRowPerPage()).append(",").append(page.getRowPerPage());
			logger.debug("分页查询SQL：" + sqlPage);
			try {
				PreparedStatement stat = conn.prepareStatement(sqlPage.toString());
				ResultSet set = stat.executeQuery();
				boList = this.wrapResultSet(bo, set);
			} catch (SQLException e) {
				throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sqlPage.toString());
			}
		}
		return boList;
	}

	@SuppressWarnings("unchecked")
	public <T> T excute(Class<T> clz, String sql) {
		PreparedStatement stat;
		try {
			stat = conn.prepareStatement(sql);
			ResultSet set = stat.executeQuery();
			set.next();
			return (T) set.getObject(1);
		} catch (SQLException e) {
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

	public Long countQuery(String sql) {
		String countSql = "select count(*) from (" + sql + ") as tempCountSql";
		logger.debug("查询数据总条数SQL:" + countSql);
		Long count = this.excute(Long.class, countSql);
		logger.debug("获取数据总条数：" + count + "条");
		return count;
	}

	private <E> List<E> wrapResultSet(Class<E> bo, ResultSet set) {
		List<E> boList = new ArrayList<>();
		try {
			while (set.next()) {
				int columnCount = set.getMetaData().getColumnCount();
				E entity = bo.newInstance();
				for (int i = 1; i <= columnCount; i++) {
					String columnName = set.getMetaData().getColumnName(i);
					Object obj = set.getObject(i);
					String fieldName = DBUtil.modifyColumnName(columnName);
					BeanUtils.setProperty(entity, fieldName, obj);
				}
				boList.add(entity);
			}
		} catch (InstantiationException | IllegalAccessException | InvocationTargetException | SQLException e) {
			throw new PersistenceRuntimeExcption(e, "封装对象列表时失败！");
		}
		return boList;
	}

	@Override
	public ResultSet query(String sql, List<Object> params) {
		logger.debug("执行SQL：" + sql);
		try {
			PreparedStatement stat = conn.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				Object value = params.get(i);
				if (value == null) {
					continue;
				}
				stat.setObject(i + 1, value);
			}
			return stat.executeQuery();
		} catch (SQLException e) {
			logger.error(e.getMessage());
			throw new PersistenceRuntimeExcption(e, "执行SQL失败>>>>" + sql);
		}
	}

}
